WHERE狙いのキー、ORDER BY狙いのキー by yoku0825
EXPLAIN(目XPLAINでも可)でtype: ALLになるような(=テーブルスキャンの)クエリーってヤバそうじゃないですか。なんでヤバいかって、テーブルに格納されるレコードの件数に比例して(本当は線形じゃなくもっとヤバい)処理量が増えていきそうなのがある程度みんな「あ、やべっ」って感じになるじゃないですか。
type:allは邪悪、Extra: Using where: Using filesort
これは、クエリが遅いときにでるの?なんなの?
予備知識
MySQLは1つのテーブルに付き同時に1つのインデックスしかつかわない MySQLの気持ちになる
「マークごとに上から何番目にあるかチートシート作る」と思うだろう。それがindex 次の注文「チートシート使っていいからハートを並び替えて」
チートシート(index)はソート済なのでかんたんにできるよね
クエリWHERE continent = 'Asia' OREDR BY Population limit 5
WHERE狙いのキー
Where句のレンジをインデックスから取り出してソートして先頭から取り出す
ORDER BY狙いのキー
Index(ソート済)を上から取り出してWhere句を判定して先頭から取り出す
keyはindex_continent(p.47)
INDEXをつかってAsiaなレコードを取得
コードはmapを使ってこれを表現している
ORDER BYするためにクイックソートして先頭から取り出す
WHEREで十分絞り込める場合はWHERE狙い
ORDER BY狙いだとlimit 5を満たすまでスキャンしようとする
ORDER BY狙いのキーはfilesortがない(indexはソート済なのでそれを使う)が、limitで指定した個数出るまでWHEREの比較が必要
populationでソート済のINDEXをつかうのでfilesortの必要なし
スライドでEXPLAINのkeyがindex_populationになっているのに注意(p.56)
p.72 WHEREとORDER BYの両方をカバーするキー(複合index)をはる 地域ごとに、レンジがソート済で入っているindexをつくると
WHEREの地域でレンジを取りだす(whereは1回)→indexに沿って行を取り出す(filesort不要)
スライドの補足
map['地名']にはレンジ => 場所がhash mapになっている
selfは自分自身を表していて、全てを取得するときに使う(p.68)
keyはindex_continent_population
狙ったクエリとそうでないクエリで100倍ぐらい性能変わるのがザラ
ここまでの知識でMySQLのJOINを眺める
SELECT * FROM Country INNER JOIN CountryLanguage ON Country.Code = CountryLanguage.CountryCode WHERE Country.continent = 'Asia' ORDER BY CountryLanguage.Percentage Limit 5;
スキャンジョインだと、外側のテーブルの行数×内側のテーブルの行数評価が必要(おそすぎ)(p.78)
直感的に、WHEREとORER BYのカラムにキーを貼ってみる(p.85)
whereのcontinentに対するindex
orderybyの(countorycode, percentage)の複合index
これはWHERE狙いのキーになる(なぜ)
ORDER BYをindexで解決するには、そのカラムが外部表になければならない 今回の場合はORDER BYしているCountryLanguage.Percentageのテーブルが外部表になってほしい
WHERE狙い(p.93)
https://gyazo.com/8729e27b9da793c481ae87fc363cfef8
ORDER BY狙い(p.102)
https://gyazo.com/97e86561b727fdf41ea72bd8f18ac821
逆からまとめ
CountryLanguageが外部表になってほしい
percentageでORDER BYするときにfilesortしたくない
このためにはINDEXの貼り方を
orderbyのpercentage
whereの(code, continent)
にする必要がある
kadoyau.icon これはどう考えればいいの?
内部表にしたい方を複合インデックスにすればいい?
両方複合INDEXだったらどうなる?